import { useEffect } from 'react'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import * as CANNON from 'cannon-es';

import { CannonEsDebuggerPro } from '@vladkrutenyuk/cannon-es-debugger-pro';

function App() {
    useEffect(() => {

        // 创建世界
        const scene = new THREE.Scene();
        // 创建相机
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 设置相机位置 
        camera.position.z = 0;
        camera.position.x = 15;
        camera.position.y = 15;
        camera.lookAt(0, 20, 0); // 设置相机朝向


        const root = new THREE.Group();
        scene.add(root); // 将根节点添加到场景中

        // 创建两个数组更新物理世界和threejs世界
        const cannonBodies = [];
        const threeObjects = [];


        // 创建物理世界
        const world = new CANNON.World();
        // 允许休眠
        world.allowSleep = true;

        const color = 0xe60c0c; // or 'rgb(228, 14, 88)', '#e60c0c', 'red'
        const offset = 0.009;
        const cannonDebugger = new CannonEsDebuggerPro(root, world, color, offset);

        // 物理世界分组
        const group1 = 1; // 物理世界分组1
        const group2 = 2; // 物理世界分组2
        const group3 = 4; // 物理世界分组3
        const group4 = 8; // 物理世界分组4

        {
            // 设置重力
            world.gravity.set(0, -9.82, 0); // m/s²


            // 添加物理材质
            const boxMaterial = new CANNON.Material('boxMaterial'); // 创建材质
            boxMaterial.friction = 0; // 摩擦力
            // boxMaterial.restitution = 0.9; // 弹性

            // 添加光滑物理材质
            const boxSlipperyMaterial = new CANNON.Material('boxSlipperyMaterial');
            boxSlipperyMaterial.friction = 0; // 摩擦力

            // 添加弹性物理材质
            const boxElasticityMaterial = new CANNON.Material('boxElasticityMaterial');
            boxElasticityMaterial.friction = 0; // 摩擦力
            boxElasticityMaterial.restitution = 0.9; // 弹性

            {
                // 创建十个正方形
                const boxShape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.05));

                let lastBody = null; // 上一个物体
                for (let i = 0; i < 10; i++) {
                    const boxBody = new CANNON.Body({
                        mass: i == 9 ? 0 : 1, // 质量
                        position: new CANNON.Vec3(0, 2 + i + (i * 0.2), 0), // 初始位置
                        material: boxMaterial, // 使用摩擦力材质
                        collisionFilterGroup: group1, // 物理分组
                    });
                    boxBody.addShape(boxShape);
                    world.addBody(boxBody);
                    cannonBodies.push(boxBody);

                    {
                        // 创建threejs物体
                        const boxGeometry = new THREE.BoxGeometry(1, 1, 0.1);
                        const boxMaterial = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
                        const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial);
                        root.add(boxMesh); // 将物体添加到场景中

                        // 将物理世界和threejs世界的物体添加到数组中
                        threeObjects.push(boxMesh);
                    }

                    // 物体之间的约束
                    if (lastBody) {
                        const constraint = new CANNON.PointToPointConstraint(
                            lastBody, // 上一个物体
                            new CANNON.Vec3(-0.5, 0.6, 0), // 上一个物体的连接点
                            boxBody, // 当前物体
                            new CANNON.Vec3(-0.5, -0.6, 0), // 当前物体的连接点
                        )
                        world.addConstraint(constraint); // 添加约束

                        
                        const constraint1 = new CANNON.PointToPointConstraint(
                            lastBody, // 上一个物体
                            new CANNON.Vec3(0.5, 0.6, 0), // 上一个物体的连接点
                            boxBody, // 当前物体
                            new CANNON.Vec3(0.5, -0.6, 0), // 当前物体的连接点
                        )
                        world.addConstraint(constraint1); // 添加约束
                    }
                    lastBody = boxBody; // 更新上一个物体
                }

                {
                    // 创建圆球撞击门帘
                    const sphereShape = new CANNON.Sphere(0.5);
                    const sphereBody = new CANNON.Body({
                        mass: 1, // 质量
                        position: new CANNON.Vec3(0, 10, 3), // 初始位置
                        material: boxMaterial, // 使用摩擦力材质
                        shape: sphereShape, // 物体形状
                    });
                    world.addBody(sphereBody);

                    cannonBodies.push(sphereBody);

                    // 创建threejs物体
                    const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
                    const sphereMaterial = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
                    const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
                    root.add(sphereMesh); // 将物体添加到场景中
                    threeObjects.push(sphereMesh);

                    sphereBody.applyLocalImpulse(new CANNON.Vec3(0, 0, -30), new CANNON.Vec3(0, 0, 0)); // 给圆球施加冲击力
                }
            }

            // 添加地面
            {
                // const groundShape = new CANNON.Box(new CANNON.Vec3(5, 0.05, 5));
                // const groundBody = new CANNON.Body({
                //     mass: 0, // 质量为0表示静止物体
                //     position: new CANNON.Vec3(0, -0.5, 0), // 初始位置
                //     material: boxMaterial, // 使用摩擦力材质
                //     collisionFilterGroup: group4, // 物理分组
                // });
                // groundBody.addShape(groundShape);
                // world.addBody(groundBody);

                // 创建平面
                const planeShape = new CANNON.Plane();
                const planeBody = new CANNON.Body({
                    mass: 0, // 质量为0表示静止物体
                    position: new CANNON.Vec3(0, -0.5, 0), // 初始位置
                    material: boxMaterial, // 使用摩擦力材质
                    collisionFilterGroup: group4, // 物理分组
                });
                // 设置平面的旋转
                planeBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); // 绕x轴旋转90度
                planeBody.addShape(planeShape);
                world.addBody(planeBody);

            }

        }

        {
            {


            }

            {
                // 创建平面
                const planeShape = new THREE.BoxGeometry(10, 0.1, 10);
                const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
                const plane = new THREE.Mesh(planeShape, planeMaterial);
                // 设置平面位置
                plane.position.y = -0.5;
                // 将平面添加到场景中
                scene.add(plane);
            }
        }



        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 将渲染器添加到DOM中
        document.getElementById('app').appendChild(renderer.domElement);

        // 添加轨道控制器
        const controls = new OrbitControls(camera, renderer.domElement);

        // 创建动画函数
        const animate = function () {
            // 更新物理世界
            world.step(1 / 60); // 60fps
            // 更新threejs世界
            for (let i = 0; i < cannonBodies.length; i++) {
                const body = cannonBodies[i];
                const mesh = threeObjects[i];
                // 更新threejs物体的位置和旋转
                mesh.position.copy(body.position);
                mesh.quaternion.copy(body.quaternion);
            }
            cannonDebugger.update(); // 更新调试器

            // 更新轨道控制器
            controls.update();


            requestAnimationFrame(animate);

            // 渲染场景
            renderer.render(scene, camera);
        };
        // 调用动画函数
        animate();


        return () => {
            // 清除渲染器
            renderer.dispose();
            // 清除场景
            scene.clear();
            // 清除相机
            camera.clear();
            // 清除渲染器DOM
            const app = document.getElementById('app');
            if (app) {
                app.removeChild(renderer.domElement);
            }

        }
    }, [])
    return (
        <div id='app'>

        </div>
    )
}

export default App
